package yl.hs.bmipfull.service.finance.impl;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import yl.hs.bmipfull.daos.finance.ISettleAdditionDao;
import yl.hs.bmipfull.daos.finance.ISettleOrderDao;
import yl.hs.bmipfull.daos.finance.IShipSettleDetailDao;
import yl.hs.bmipfull.daos.finance.IShipSettleMainDao;
import yl.hs.bmipfull.daos.salemanage.ISaleContractDao;
import yl.hs.bmipfull.daos.system.IAppSettingDao;
import yl.hs.bmipfull.pojo.finance.*;
import yl.hs.bmipfull.pojo.production.ProductShipOrderEntity;
import yl.hs.bmipfull.service.finance.IShipSettleService;
import yl.hs.bmipfull.utils.*;
import yl.hs.bmipfull.utils.datastate.ActionType;
import yl.hs.bmipfull.viewmodels.PageQuery;
import yl.hs.bmipfull.viewmodels.PageResult;
import yl.hs.bmipfull.viewmodels.SubmitModel;
import yl.hs.bmipfull.viewmodels.finance.OrderState;
import yl.hs.bmipfull.viewmodels.salemanmage.ConstructionSignModel;
import yl.hs.bmipfull.viewmodels.salemanmage.TimeGroupVO;

import java.math.BigDecimal;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;

@Slf4j
@Service
public class ShipSettleServiceImpl extends FinanceService implements IShipSettleService {


    @Override
    public PageResult<Map<String,Object>> queryPage(PageQuery pageQuery, int rowNum, int page) throws Exception {
        PageResult<Map<String,Object>>  result;
        pageQuery.checkSortSides(ProductShipOrderEntity.class);
        var glpcCateSN=HsApp.getSystemSet(CK.AggregateTakeoutSN);
        var filters = SearchFilterEngine.generateQueryList(pageQuery.getFilters(), ProductShipOrderEntity.class);
        List<Map<String,Object>> data = new ArrayList<>();
        if(rowNum>0){
            result = new PageResult<>(rowNum);
            pageQuery.getQuery().put("querySkip", (page - 1) * rowNum);
            pageQuery.getQuery().put("pageSize", rowNum);
            result.setRecords(dao.queryCountByCondition(pageQuery.getQuery(),filters));
            result.setPage(page);
            var list = dao.queryPage(pageQuery.getQuery(),filters);

            for (ShipSettleMainEntity item : list) {
                data.add(Tl.toMap(item));
            }
        }
        else
        {
            var betonSet = HsApp.getSystemSet(CK.BetonSysCode);//商砼类别编号
            var mortarSet = HsApp.getSystemSet(CK.MortarSnSysCode);//商砼类别编号
            if(pageQuery.getQuery().get("productCateSN")==null)
            {
                throw  new Exception("搜索条件中缺少productCateSN");
            }
            var searchQuery = pageQuery.getQuery();
            var defFilters = pageQuery.getFilters();
            if(defFilters!=null && defFilters.size()>0){
                var startTimeOpt = defFilters.stream().filter(t->t.getField().equals("startTime")).findFirst();
                var endTimeOpt = defFilters.stream().filter(t->t.getField().equals("endTime")).findFirst();
                startTimeOpt.ifPresent(queryFilter -> searchQuery.put("startTime", queryFilter.getSearchVal()));
                endTimeOpt.ifPresent(queryFilter -> searchQuery.put("endTime", queryFilter.getSearchVal()));
            }
            var productCateSN = searchQuery.get("productCateSN");
            var orderList = dao.queryTempSettleOrders(searchQuery,filters);
            var contractList = dao.querySettleContract(searchQuery,filters);
            var contractAddition = dao.querySettleContractAddition(searchQuery,filters);
            var contractLastSettle = dao.queryContractSettleLast(searchQuery,filters);
            var settleReceiptList = dao.queryContractReceiptList(searchQuery,filters);//收款信息
            result = new PageResult<>(contractList.size()>0?contractList.size():1);
            result.setRecords(contractList.size());
            result.setPage(page);


            for (var cti : contractList) {
                ShipSettleMainEntity item = new ShipSettleMainEntity();
                item.setSn(cti.getSn());
                var orders = orderList.stream().filter(t -> cti.getSn().equals(t.getContractSN()) && t.getState()==10).collect(Collectors.toList());

                item.setContractRemark(cti.getRemark());
                item.setContractSN(cti.getSn());
                item.setContractingUnit(cti.getContractingUnit());
                item.setCustomerName(cti.getCustomerName());
                item.setCustomerSN(cti.getCustomerSN());
                item.setProductCateSN(pageQuery.getQuery().get("productCateSN").toString());
                item.setSettleTime(new Date());
                item.setSettleType(cti.getSettleInterval() == null || cti.getSettleInterval() == 0 ? "自定义" : String.format("本月%02d日", cti.getSettleInterval()));
                Date min, max;
                var searchStart = pageQuery.getQuery().get("startTime");
                var searchEnd = pageQuery.getQuery().get("endTime");
                var dataParse = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                if (searchStart == null || "".equals(searchStart)) {
                    min = orders.stream().map(ProductShipOrderEntity::getOutTime).filter(Objects::nonNull).min(Date::compareTo).get();
                } else {
                    min = dataParse.parse(searchStart.toString());
                }
                if (searchEnd == null || "".equals(searchEnd)) {
                    max = orders.stream().map(ProductShipOrderEntity::getOutTime).filter(Objects::nonNull).max(Date::compareTo).get();
                } else {
                    max = dataParse.parse(searchEnd.toString());
                }
                item.setStartTime(min);
                item.setEndTime(max);
                var lastSettle = contractLastSettle.stream().filter(t -> t.getContractSN().equals(cti.getSn())).findFirst();
                BigDecimal previousAmount = BigDecimal.valueOf(0.0),
                        totalReceivedAmount = BigDecimal.valueOf(0.0), currentReceivedAmount = BigDecimal.valueOf(0.0),
                        totalQuantity = BigDecimal.valueOf(0.0), currentQuantity = BigDecimal.valueOf(0.0),
                        totalAmount = BigDecimal.valueOf(0.0), currentAmount = BigDecimal.valueOf(0.0),
                        unAQuantity = BigDecimal.valueOf(0.0), unAAmount = BigDecimal.valueOf(0.0),//已审核未结算
                        unQuantity = BigDecimal.valueOf(0.0), unAmount = BigDecimal.valueOf(0.0);//未审核未结算
                int totalOrderCount = 0,  unAOrderCount = 0, unOrderCount = 0;
                item.setPriceChannel(cti.getChannel());
                item.setSettleWay("周期");
                if (lastSettle.isPresent()) {
                    var last = lastSettle.get();
                    previousAmount = last.getCurrentAmount();
                    totalReceivedAmount = last.getTotalReceivedAmount();
                    totalQuantity = last.getTotalQuantity();
                    totalAmount = last.getTotalAmount();
                    totalOrderCount = last.getTotalOrderCount();
                } else {
                    if (cti.getInitialBatch() != null) {
                        totalQuantity = totalQuantity.add(cti.getInitialBatch());
                    }
                    if (cti.getInitialMoney() != null) {
                        totalAmount = totalAmount.add(cti.getInitialMoney());
                    }
                }
                for (ShipSettleTemp order : orders) {
                    BigDecimal price;
                    if (order.getProductCateSN().equals(glpcCateSN)){
                        price=order.getShipmentReviewPrice();
                    }else{
                        price=order.getPrice();
                    }
                    if (order.getState() == 10) {//已审核
                        if(productCateSN!=null && productCateSN.equals(betonSet)) {
                            currentQuantity = currentQuantity.add(order.getShipmentReviewWeight());
                            currentAmount = currentAmount.add(order.getShipmentReviewWeight().multiply(price));
                        }
                        else{
                            currentQuantity = currentQuantity.add(order.getShipmentReviewWeight());
                            currentAmount = currentAmount.add(order.getShipmentReviewWeight().multiply(price));
                        }
                    }
                }
                var contractReceiptAmountObj = settleReceiptList.stream().filter(t -> cti.getSn().equals(t.getSn())).findFirst();
                if (contractReceiptAmountObj.isPresent()) {
                    currentReceivedAmount = contractReceiptAmountObj.get().getAmount();
                    totalReceivedAmount = totalReceivedAmount.add(currentReceivedAmount);
                }
                totalOrderCount += orders.size();
                item.setCurrentQuantity(currentQuantity);
                item.setTotalQuantity(totalQuantity.add(currentQuantity));
                item.setPreviousAmount(previousAmount);
                item.setCurrentAmount(currentAmount);
                item.setTotalAmount(totalAmount.add(currentAmount));
                item.setTotalReceivedAmount(totalReceivedAmount);
                item.setCurrentReceivedAmount(currentReceivedAmount);
                item.setCurrentOrderCount(orders.size());
                item.setTotalOrderCount(totalOrderCount);
                item.setRemark("");
                item.setProductCateName("");
                item.setState((short) 1);
                item.setTags("");
                var dataMap = Tl.toMap(item);
                dataMap.put("unSettleApprovedQuantity", unAQuantity);
                dataMap.put("unSettleApprovedAmount", unAAmount);
                dataMap.put("unSettleApprovedOrderCount", unAOrderCount);
                dataMap.put("unApprovedQuantity", unQuantity);
                dataMap.put("unApprovedAmount", unAmount);
                dataMap.put("unApprovedOrderCount", unOrderCount);
                data.add(dataMap);
            }
        }
        result.setData(data);
        return result;
    }


    @Override
    public PageResult<Map<String, Object>> queryPageConstruction(PageQuery pageQuery, int rowNum, int page) throws ParseException, Exception {
        PageResult<Map<String,Object>>  result;
        pageQuery.checkSortSides(ProductShipOrderEntity.class);
        var glpcCateSN=HsApp.getSystemSet(CK.AggregateTakeoutSN);
        List<Map<String,Object>> data = new ArrayList<>();
        var snList=getConstructionContractSN();
        List<Map<String,Object>> filter=new ArrayList<>();
        if(snList.size()<=0){
            result=new PageResult<>(rowNum);
            return  result;
        }
        if(rowNum>0){
            result = new PageResult<>(rowNum);
            pageQuery.getQuery().put("querySkip", (page - 1) * rowNum);
            pageQuery.getQuery().put("pageSize", rowNum);

            result.setRecords(dao.queryCountByContractSN(pageQuery.getQuery(),filter,snList));
            result.setPage(page);
            var list = dao.queryPageContractSN(pageQuery.getQuery(),filter,snList);

            for (ShipSettleMainEntity item : list) {
                data.add(Tl.toMap(item));
            }
        }
        else
        {
            if(pageQuery.getQuery().get("productCateSN")==null)
            {
                throw  new Exception("搜索条件中缺少productCateSN");
            }
            pageQuery.getQuery().put("contractSN",snList.get(0));
            var searchQuery = pageQuery.getQuery();
            var defFilters = pageQuery.getFilters();
            if(defFilters!=null && defFilters.size()>0){
                var startTimeOpt = defFilters.stream().filter(t->t.getField().equals("startTime")).findFirst();
                var endTimeOpt = defFilters.stream().filter(t->t.getField().equals("endTime")).findFirst();
                if(startTimeOpt.isPresent()){
                    searchQuery.put("startTime",startTimeOpt.get().getSearchVal());
                }
                if(endTimeOpt.isPresent()){
                    searchQuery.put("endTime",endTimeOpt.get().getSearchVal());
                }
            }
            var productCateSN = searchQuery.get("productCateSN");
            var orderList = dao.queryTempSettleOrders(searchQuery,null);
            var contractList = dao.querySettleContract(searchQuery,null);
            var contractPPAdjust = dao.querySettleContractPPAdjust(searchQuery,null);
            var contractPrice = dao.querySettleContractDetails(searchQuery,null);
            var contractAddition = dao.querySettleContractAddition(searchQuery,null);
            var contractAdjust = dao.querySettleContractAdjust(searchQuery,null);
            var productPrice = dao.querySettleProductPrice(searchQuery,null);
            var contractLastSettle = dao.queryContractSettleLast(searchQuery,null);
            var settleReceiptList = dao.queryContractReceiptList(searchQuery,null);//收款信息
            result = new PageResult<>(contractList.size()>0?contractList.size():1);
            result.setRecords(contractList.size());
            result.setPage(page);


            for (var cti : contractList) {
                ShipSettleMainEntity item = new ShipSettleMainEntity();
                item.setSn(cti.getSn());
                var orders = orderList.stream().filter(t -> cti.getSn().equals(t.getContractSN())).collect(Collectors.toList());
                var additions = contractAddition.stream().filter(t -> cti.getSn().equals(t.getContractSN())).collect(Collectors.toList());
                item.setContractRemark(cti.getRemark());
                item.setContractSN(cti.getSn());
                item.setContractingUnit(cti.getContractingUnit());
                item.setCustomerName(cti.getCustomerName());
                item.setCustomerSN(cti.getCustomerSN());
                item.setProductCateSN(pageQuery.getQuery().get("productCateSN").toString());
                item.setSettleTime(new Date());
                item.setSettleType(cti.getSettleInterval() == null || cti.getSettleInterval() == 0 ? "自定义" : String.format("本月%02d日", cti.getSettleInterval()));
                Date min, max;
                var searchStart = pageQuery.getQuery().get("startTime");
                var searchEnd = pageQuery.getQuery().get("endTime");
                var dataParse = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                if (searchStart == null || "".equals(searchStart)) {
                    min = orders.stream().map(ProductShipOrderEntity::getOutTime).filter(Objects::nonNull).min(Date::compareTo).get();
                } else {
                    min = dataParse.parse(searchStart.toString());
                }
                if (searchEnd == null || "".equals(searchEnd)) {
                    max = orders.stream().map(ProductShipOrderEntity::getOutTime).filter(Objects::nonNull).max(Date::compareTo).get();
                } else {
                    max = dataParse.parse(searchEnd.toString());
                }
                item.setStartTime(min);
                item.setEndTime(max);
                var lastSettle = contractLastSettle.stream().filter(t -> t.getContractSN().equals(cti.getSn())).findFirst();
                BigDecimal previousAmount = BigDecimal.valueOf(0.0),
                        totalReceivedAmount = BigDecimal.valueOf(0.0), currentReceivedAmount = BigDecimal.valueOf(0.0),
                        totalQuantity = BigDecimal.valueOf(0.0), currentQuantity = BigDecimal.valueOf(0.0),
                        totalAmount = BigDecimal.valueOf(0.0), currentAmount = BigDecimal.valueOf(0.0),
                        unAQuantity = BigDecimal.valueOf(0.0), unAAmount = BigDecimal.valueOf(0.0),//已审核未结算
                        unQuantity = BigDecimal.valueOf(0.0), unAmount = BigDecimal.valueOf(0.0);//未审核未结算
                int totalOrderCount = 0, currentOrderCount = 0, unAOrderCount = 0, unOrderCount = 0;
                item.setPriceChannel(cti.getChannel());
                item.setSettleWay("周期");
                if (lastSettle.isPresent()) {
                    var last = lastSettle.get();
                    previousAmount = last.getCurrentAmount();
                    totalReceivedAmount = last.getTotalReceivedAmount();
                    totalQuantity = last.getTotalQuantity();
                    totalAmount = last.getTotalAmount();
                    totalOrderCount = last.getTotalOrderCount();
                } else {
                    if (cti.getInitialBatch() != null) {
                        totalQuantity = totalQuantity.add(cti.getInitialBatch());
                    }
                    if (cti.getInitialMoney() != null) {
                        totalAmount = totalAmount.add(cti.getInitialMoney());
                    }
                }


                for (ShipSettleTemp order : orders) {
                    BigDecimal price=BigDecimal.ZERO;
                    if (order.getProductCateSN().equals(glpcCateSN)){
                        price=order.getShipmentReviewPrice();
                    }else{
                        price=order.getPrice();
                    }
                    BigDecimal orderQuantity = BigDecimal.valueOf(0.00), orderWeight = BigDecimal.valueOf(0.00);
                    if (order.getState() == 10) {//已审核
                        currentQuantity = currentQuantity.add(order.getShipmentReviewQuantity());
                        currentAmount = currentAmount.add(order.getShipmentReviewQuantity().multiply(price));
                        currentOrderCount++;
                    }
                }
                var contractReceiptAmountObj = settleReceiptList.stream().filter(t -> cti.getSn().equals(t.getSn())).findFirst();
                if (!contractReceiptAmountObj.isEmpty()) {
                    currentReceivedAmount = contractReceiptAmountObj.get().getAmount();
                    totalReceivedAmount = totalReceivedAmount.add(currentReceivedAmount);
                }
                totalOrderCount += currentOrderCount;
                item.setCurrentQuantity(currentQuantity);
                item.setTotalQuantity(totalQuantity.add(currentQuantity));
                item.setPreviousAmount(previousAmount);
                item.setCurrentAmount(currentAmount);
                item.setTotalAmount(totalAmount.add(currentAmount));
                item.setTotalReceivedAmount(totalReceivedAmount);
                item.setCurrentReceivedAmount(currentReceivedAmount);
                item.setCurrentOrderCount(currentOrderCount);
                item.setTotalOrderCount(totalOrderCount);
                item.setRemark("");
                item.setProductCateName("");
                item.setState((short) 1);
                item.setTags("");
                var dataMap = Tl.toMap(item);
                dataMap.put("unSettleApprovedQuantity", unAQuantity);
                dataMap.put("unSettleApprovedAmount", unAAmount);
                dataMap.put("unSettleApprovedOrderCount", unAOrderCount);
                dataMap.put("unApprovedQuantity", unQuantity);
                dataMap.put("unApprovedAmount", unAmount);
                dataMap.put("unApprovedOrderCount", unOrderCount);
                data.add(dataMap);
            }
        }
        result.setData(data);
        return result;
    }


    @Override
    public Map<String, Object> querySettleDetailsBySettleSN(String settleSN) {
        Map<String,Object> result = new HashMap<>();
        result.put("details", detailDao.queryDetailBySettleSN(settleSN));
        result.put("additions",additionDao.queryAdditionsBySettleSN(settleSN));
        return result;
    }
    @Override
    public List<ProductShipOrderEntity> querySettleOrdersBySnList(String snList){
        return dao.querySettleOrdersBySnArray(snList.split(","));
    }

    @Override
    public List<Map<String,Object>> queryTempSettleDetails(String contractSN, String productCateSN, String startDate, String endDate) throws ParseException {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        var betonSet = HsApp.getSystemSet(CK.BetonSysCode);//商砼类别编号
        var mortarSet = HsApp.getSystemSet(CK.MortarSnSysCode);//商砼类别编号
        var glpsCateSN = HsApp.getSystemSet(CK.AggregateTakeoutSN);//骨料破碎类别编号
        var settleFlag = (betonSet!=null && betonSet.equals(productCateSN));
        Date start = null,end=null;
        if(!Tl.isEmpty(startDate)) {
            start = sdf.parse(startDate);
        }
        if(!Tl.isEmpty(endDate)) {
            end = sdf.parse(endDate);
            Calendar   calendar = new GregorianCalendar();
            calendar.setTime(end);
            calendar.add(Calendar.SECOND,2);
            end = calendar.getTime();
        }
        List<Map<String,Object>> list = new ArrayList<>();
        var data = detailDao.queryTempDetails(contractSN,productCateSN,start,end);
        for(var o:data){
            if (o.getProductCateSN().equals(glpsCateSN)){
                if(o.getShipmentReviewPrice()!=null && o.getShipmentReviewPrice().doubleValue()!=0){
                    o.setPrice(o.getShipmentReviewPrice());
                }

            }
            if(o.getBuildPosition()==null){
                o.setBuildPosition("");
            }
            if(o.getAccountProductSN()==null){
                o.setAccountProductSN("");
            }
            if(o.getAccountProductName()==null){
                o.setAccountProductName("");
            }
            if(o.getAccountProductSpec()==null){
                o.setAccountProductSpec("");
            }
            if(o.getPrice()==null){
                o.setPrice(BigDecimal.ZERO);
            }
        }
        if(betonSet!=null&&betonSet.equals(productCateSN)){
            var groupData = data.stream().collect(
                    Collectors.groupingBy(ShipSettleTemp::getBuildPosition,
                            Collectors.groupingBy(ShipSettleTemp::getAccountProductSN,
                                    Collectors.groupingBy(ShipSettleTemp::getAccountProductName,
                                            Collectors.groupingBy(ShipSettleTemp::getAccountProductSpec,
                                                    Collectors.groupingBy(ShipSettleTemp::getPrice,
                                                            Collectors.groupingBy(ShipSettleTemp::getProductTags,Collectors.toList())))))));
            for(var buildPosition : groupData.keySet()){
                var productSNGroup = groupData.get(buildPosition);
                for (var productSN : productSNGroup.keySet()){
                    var productNameGroup = productSNGroup.get(productSN);
                    for (var productName: productNameGroup.keySet()){
                        var productSpecGroup = productNameGroup.get(productName);
                        for (var productSpec : productSpecGroup.keySet()){
                            var priceGroup = productSpecGroup.get(productSpec);
                            for (var price : priceGroup.keySet()){
                                var tagGroup = priceGroup.get(price);
                                for (var tags:tagGroup.keySet()) {
                                    var detail = new ShipSettleDetailEntity();
                                    var orders = tagGroup.get(tags);
                                    detail.setOrderCount(orders.size());
                                    detail.setBuildPosition(buildPosition);
                                    detail.setProductSN(productSN);
                                    detail.setProductName(productName);
                                    detail.setProductSpec(productSpec);
                                    detail.setPrice(price);
                                    var totalQuantity = orders.stream().map(ProductShipOrderEntity::getShipmentReviewQuantity).reduce(BigDecimal.ZERO,BigDecimal::add);
                                    detail.setTotalQuantity(totalQuantity);
                                    var totalWeight = orders.stream().map(ProductShipOrderEntity::getShipmentReviewWeight).reduce(BigDecimal.ZERO,BigDecimal::add);
                                    detail.setTotalWeight(totalWeight);
                                    var minDate = orders.stream().min(Comparator.comparing(ShipSettleTemp::getOutTime));
                                    var maxDate = orders.stream().max(Comparator.comparing(ShipSettleTemp::getOutTime));
                                    String minTime = "",maxTime="";
                                    var dateFormat = new SimpleDateFormat("yyyy-MM-dd");
                                    if(minDate.isPresent()){
                                        minTime = dateFormat.format(minDate.get().getOutTime());
                                    }
                                    if(maxDate.isPresent()){
                                        maxTime = dateFormat.format(maxDate.get().getOutTime());
                                    }
                                    detail.setTitle(String.format("%s 至 %s",minTime,maxTime));
                                    if(settleFlag){
                                        detail.setAmount(totalQuantity.multiply(price));
                                    }else{
                                        detail.setAmount(totalWeight.multiply(price));
                                    }

                                    var map = detail.toMap();
                                    map.put("orderSnArray",orders.stream().map(ProductShipOrderEntity::getSn));
                                    list.add(map);
                                }
                            }
                        }
                    }
                }
            }
        } else if (glpsCateSN!=null && glpsCateSN.equals(productCateSN)) {
            var groupData = data.stream().collect(
                    Collectors.groupingBy(ShipSettleTemp::getAccountProductSN,
                            Collectors.groupingBy(ShipSettleTemp::getAccountProductName,
                                    Collectors.groupingBy(ShipSettleTemp::getAccountProductSpec,
                                            Collectors.groupingBy(ShipSettleTemp::getPrice,
                                                    Collectors.toList())))));
            for (var productSN : groupData.keySet()){
                var productNameGroup = groupData.get(productSN);
                for (var productName: productNameGroup.keySet()){
                    var productSpecGroup = productNameGroup.get(productName);
                    for (var productSpec : productSpecGroup.keySet()){
                        var priceGroup = productSpecGroup.get(productSpec);
                        for (var price : priceGroup.keySet()){
                            var orders = priceGroup.get(price);
                            var detail = new ShipSettleDetailEntity();
                            detail.setOrderCount(orders.size());
                            detail.setProductSN(productSN);
                            detail.setProductName(productName);
                            detail.setProductSpec(productSpec);
                            detail.setPrice(price);
                            var totalQuantity = orders.stream().map(ProductShipOrderEntity::getShipmentReviewQuantity).reduce(BigDecimal.ZERO,BigDecimal::add);
                            detail.setTotalQuantity(totalQuantity);
                            var totalWeight = orders.stream().map(ProductShipOrderEntity::getShipmentReviewWeight).reduce(BigDecimal.ZERO,BigDecimal::add);
                            detail.setTotalWeight(totalWeight);
                            var minDate = orders.stream().min(Comparator.comparing(ShipSettleTemp::getOutTime));
                            var maxDate = orders.stream().max(Comparator.comparing(ShipSettleTemp::getOutTime));
                            String minTime = "",maxTime="";
                            var dateFormat = new SimpleDateFormat("yyyy-MM-dd");
                            if(minDate.isPresent()){
                                minTime = dateFormat.format(minDate.get().getOutTime());
                            }
                            if(maxDate.isPresent()){
                                maxTime = dateFormat.format(maxDate.get().getOutTime());
                            }
                            detail.setTitle(String.format("%s 至 %s",minTime,maxTime));
                            if(settleFlag){
                                detail.setAmount(totalQuantity.multiply(price));
                            }else{
                                detail.setAmount(totalWeight.multiply(price));
                            }

                            var map = detail.toMap();
                            map.put("orderSnArray",orders.stream().map(ProductShipOrderEntity::getSn));
                            list.add(map);
                        }
                    }
                }
            }
        } else{
            var groupData = data.stream().collect(
                            Collectors.groupingBy(ShipSettleTemp::getAccountProductSN,
                                    Collectors.groupingBy(ShipSettleTemp::getAccountProductName,
                                            Collectors.groupingBy(ShipSettleTemp::getAccountProductSpec,
                                                    Collectors.groupingBy(ShipSettleTemp::getPrice,
                                                            Collectors.toList())))));
            for (var productSN : groupData.keySet()){
                var productNameGroup = groupData.get(productSN);
                for (var productName: productNameGroup.keySet()){
                    var productSpecGroup = productNameGroup.get(productName);
                    for (var productSpec : productSpecGroup.keySet()){
                        var priceGroup = productSpecGroup.get(productSpec);
                        for (var price : priceGroup.keySet()){
                            var orders = priceGroup.get(price);
                            var detail = new ShipSettleDetailEntity();
                            detail.setOrderCount(orders.size());
                            detail.setProductSN(productSN);
                            detail.setProductName(productName);
                            detail.setProductSpec(productSpec);
                            detail.setPrice(price);
                            var totalQuantity = orders.stream().map(ProductShipOrderEntity::getShipmentReviewQuantity).reduce(BigDecimal.ZERO,BigDecimal::add);
                            detail.setTotalQuantity(totalQuantity);
                            var totalWeight = orders.stream().map(ProductShipOrderEntity::getShipmentReviewWeight).reduce(BigDecimal.ZERO,BigDecimal::add);
                            detail.setTotalWeight(totalWeight);
                            var minDate = orders.stream().min(Comparator.comparing(ShipSettleTemp::getOutTime));
                            var maxDate = orders.stream().max(Comparator.comparing(ShipSettleTemp::getOutTime));
                            String minTime = "",maxTime="";
                            var dateFormat = new SimpleDateFormat("yyyy-MM-dd");
                            if(minDate.isPresent()){
                                minTime = dateFormat.format(minDate.get().getOutTime());
                            }
                            if(maxDate.isPresent()){
                                maxTime = dateFormat.format(maxDate.get().getOutTime());
                            }
                            detail.setTitle(String.format("%s 至 %s",minTime,maxTime));
                            if(settleFlag){
                                detail.setAmount(totalQuantity.multiply(price));
                            }else{
                                detail.setAmount(totalWeight.multiply(price));
                            }

                            var map = detail.toMap();
                            map.put("orderSnArray",orders.stream().map(ProductShipOrderEntity::getSn));
                            list.add(map);
                        }
                    }
                }
            }
        }

        return  list;
    }
    @Override
    @Transactional
    public Integer cancelSettle(String settleSN){
        var result = dao.deleteBySettleSN(settleSN);
        detailDao.deleteBySettleSN(settleSN);
        additionDao.deleteBySettleSN(settleSN);
        dao.changeOrderToUnSettle(settleSN);
        orderDao.deleteBySettleSN(settleSN);
        return result;
    }
    @Override
    @Transactional
    public Integer saveSettle(SubmitModel model) throws Exception {
        var result = 0;
        var settleMainInfo = new ShipSettleMainEntity();
        Tl.getChangeLog(settleMainInfo,model.getData());
        var settleSN = queryNewSN(settleMainInfo.getClass());
        settleMainInfo.setSn(settleSN);
        settleMainInfo.setSettleTime(new Date());
        settleMainInfo.setState((short) 1);
        settleMainInfo.setPYFieldValue();
        settleMainInfo.setOrganizationCode(getDepartSN());
        if(!Tl.isEmpty(settleMainInfo.getContractSN())){
            var contract=contractDao.findBySN(settleMainInfo.getContractSN());
            settleMainInfo.setContractingUnit(contract.getContractingUnit());
        }
        var lastSettle = dao.getLastSettle(settleMainInfo.getContractSN());
        if(lastSettle!=null) {
            settleMainInfo.setPreviousAmount(lastSettle.getCurrentAmount());
            settleMainInfo.setTotalAmount(lastSettle.getTotalAmount().add(settleMainInfo.getCurrentAmount()));
            settleMainInfo.setTotalOrderCount(lastSettle.getTotalOrderCount() + settleMainInfo.getCurrentOrderCount());
            settleMainInfo.setTotalQuantity(lastSettle.getTotalQuantity().add(settleMainInfo.getCurrentQuantity()));
            settleMainInfo.setTotalReceivedAmount(lastSettle.getTotalReceivedAmount().add(settleMainInfo.getCurrentReceivedAmount()));
        }
        else {
            settleMainInfo.setTotalAmount(settleMainInfo.getCurrentAmount());
            settleMainInfo.setTotalReceivedAmount(settleMainInfo.getCurrentReceivedAmount());
            settleMainInfo.setTotalQuantity(settleMainInfo.getTotalQuantity());
            settleMainInfo.setTotalOrderCount(settleMainInfo.getTotalOrderCount());
        }

        result = dao.insertNew(settleMainInfo);
        if(result>0) {
            var detailsObj = model.getData().get("details");
            if(detailsObj!=null){
                List<Map<String,Object>> detailList = (List<Map<String, Object>>) (detailsObj);
                if(detailList.size()>0){
                    var settleOrderList = new ArrayList<SettleOrderEntity>();
                    var newSN = queryNewSN(ShipSettleDetailEntity.class);
                    for (int i = 0; i < detailList.size(); i++) {
                        var detailMap = detailList.get(i);
                        var orderSnObj = detailMap.get("orderSnArray");
                        var detailItem = new ShipSettleDetailEntity();

                        var detailSN = newSN;
                        if(i>0){
                            detailSN = queryNewSN(ShipSettleDetailEntity.class,newSN,i );
                        }

                        Tl.getChangeLog(detailItem,detailMap);
                        detailItem.setSn(detailSN);
                        detailItem.setSettleSN(settleSN);
                        detailDao.insertNew(detailItem);
                        if(orderSnObj!=null){
                            List<String> orderSNList = (List<String>) orderSnObj;
                            if(orderSNList.size()>0){
                                for (String s : orderSNList) {
                                    var settleOrder = new SettleOrderEntity();
                                    settleOrder.setSettleSN(settleSN);
                                    settleOrder.setDetailSN(detailSN);
                                    settleOrder.setOrderSN(s);
                                    settleOrderList.add(settleOrder);
                                }
                            }
                        }
                    }
                    orderDao.insertBatch(settleOrderList);
                    dao.changeOrderToSettled(settleSN);
                }
            }
            var additionsObj = model.getData().get("additions");
            if (additionsObj!=null){
                List<Map<String,Object>> additionList = (List<Map<String, Object>>) additionsObj;
                if(additionList.size()>0){
                    for (Map<String, Object> map : additionList) {
                        var additionItem = new SettleAdditionEntity();
                        var additionMap = map;
                        additionItem.setSn(queryNewSN(additionItem.getClass()));
                        Tl.getChangeLog(additionItem, additionMap);
                        additionItem.setSettleSN(settleSN);
                        additionDao.insertNew(additionItem);
                    }
                }
            }

            //仅发送财务人员
            sendConstructMessage("有新的结算单"+settleMainInfo.getSn()+"需要确认",settleMainInfo.getContractSN(),"结算单确认",(short) 2);
        }
        return  result;
    }
    @Override
    public ShipSettleMainEntity findLastByContractSn(String contractSn) {


        return dao.findLastByContractSn(contractSn);
    }

    @Override
    public ShipSettleMainEntity findBySn(String sn) {
        return dao.findBySN(sn);
    }

    @Override
    public int updateExportCount(String sn) {
        int result=0;
        var entity=dao.findBySN(sn);
        if(entity!=null){
            entity.setExportCount(entity.getExportCount()+1);
            result=dao.update(entity);
        }
        return result;
    }

    @Override
    public List<ProductShipOrderEntity> querySettleOrdersBySettleSN(String settleSN){
        return dao.querySettleOrdersBySettleSN(settleSN);
    }
    @Override
    public List<TimeGroupVO> getSetTimeGroup() {
        return VoUtil.groupTime(dao.getSetTime());
    }
    @Override
    public PageResult<ShipSettleMainEntity> queryConstructionPage(PageQuery query, int rowNum, int page) throws Exception {
        PageResult<ShipSettleMainEntity>  result = new PageResult<>(rowNum);
        query.checkSortSides(ShipSettleMainEntity.class);
        query.getQuery().put("querySkip", (page - 1) * rowNum);
        query.getQuery().put("pageSize", rowNum);
        var snList = getConstructionContractSN();
        if(snList.size()>0) {
            result.setRecords(dao.queryCountByCustom(query.getQuery(), snList));
            result.setData(dao.queryDataByCustom(query.getQuery(), snList));
        }
        else{
            result.setRecords(0);
            result.setData(new ArrayList<>());
        }
        result.setPage(page);
        return result;
    }
    @Override
    public Integer GetConstructionNotSignedCount(PageQuery query) throws Exception {
        var snList = getConstructionContractSN();
        if(snList.size()>0) {
            query.getQuery().put("state",1);
            return dao.queryCountByCustom(query.getQuery(), snList);
        }
        return 0;
    }
    @Override
    public Integer saveSignInfo(ConstructionSignModel model) {
        var order = dao.findBySN(model.getOrderSN());
        if (order != null) {
            var user = HsApp.getCurrent();
            order.setSigner(user.getUserName());
            order.setSigningTime(new Date());
            order.setSignSvg(model.getSignSVG());
            order.setSignWay(model.getSignWay());
            order.setSignRemark(model.getSignRemark());
            var dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm");

            order.setState(OrderState.SIGED.code);
            var result = dao.update(order);
            if (result > 0) {
                var logContent = String.format(user.getUserName() + "提交了结算单" + order.getSn() + "的确认信息：" + user.getUserName() +
                        "在" + dateFormat.format(order.getSigningTime()) + "通过" + model.getSignWay() + "确认");
                writeLog(ActionType.UPDATE,order.getSn(),logContent,Tl.toJson(model),order.getClass());
                sendSysFeatherMessage(order.getCustomerName()+"的结算单"+order.getSn()+"已确认",CK.Product_Ship_Settle_Feature,"结算单已确认");
            }
            return result;
        }
        return 0;
    }
    @Override
    public List<ShipSettleTemp> queryOrdersSettleDetails(String contractSN, String productCateSN, String startDate, String endDate) throws ParseException {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        Date start = null,end=null;
        if(!Tl.isEmpty(startDate)) {
            start = sdf.parse(startDate);
        }
        if(!Tl.isEmpty(endDate)) {
            end = sdf.parse(endDate);
            Calendar   calendar = new GregorianCalendar();
            calendar.setTime(end);
            calendar.add(Calendar.MINUTE,1);
            end = calendar.getTime();
        }
        var list=detailDao.queryTempOrdersDetails(contractSN,productCateSN,start,end);
        var glpsCateSN=HsApp.getSystemSet(CK.AggregateTakeoutSN);
        var BetonSysCode=HsApp.getSystemSet(CK.BetonSysCode);
        for (var o : list){
            if(o.getProductCateSN().equals(glpsCateSN) && o.getState()>=10){
                if(o.getShipmentReviewPrice()!=null && o.getShipmentReviewPrice().doubleValue()!=0){
                    o.setPrice(o.getShipmentReviewPrice());
                }
                o.setAmount(o.getShipmentReviewWeight().multiply(o.getPrice()));
            } else if (o.getProductCateSN().equals(BetonSysCode)) {
                if (o.getState()>=10){
                    o.setAmount(o.getShipmentReviewQuantity().multiply(o.getPrice()));
                }else{
                    o.setAmount(o.getQuantity().multiply(o.getPrice()));
                }

            }else{
                if (o.getState()>=10){
                    o.setAmount(o.getShipmentReviewWeight().multiply(o.getPrice()));
                }else{
                    o.setAmount(o.getNetWeight().multiply(o.getPrice()));
                }
            }
        }
        return list;
    }

    @Override
    public List<Map<String, Object>> queryExportOrdersBySettleSN(String settleSN) {
        return dao.queryExportOrdersBySettleSN(settleSN);
    }

    @Autowired
    IShipSettleMainDao dao;

    @Autowired
    IShipSettleDetailDao detailDao;

    @Autowired
    ISettleAdditionDao additionDao;

    @Autowired
    ISettleOrderDao orderDao;

    @Autowired
    IAppSettingDao asDao;
    @Autowired
    ISaleContractDao contractDao;
}
